/*
 * $Id: api_getmeminfo.c 50 2009-02-10 05:48:05Z hyunghwan.chung $
 *
   Copyright 2005-2009 Chung, Hyung-Hwan.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an  BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

#include <xp/sys/api.h>

#if defined(_WIN32)
	#include <pdh.h>
#elif defined(__linux)
	#include <sys/sysinfo.h>
	#include <sys/sysctl.h>
#elif defined(__FreeBSD__)
	#include <kvm.h>
	#include <fcntl.h>
	#include <sys/sysctl.h>
#elif defined(sun)||defined(__sun)
	#include <sys/sysinfo.h>
#else
	#include <sys/sysctl.h>
#endif

/* TODO: implant an option to return the size in kbytes */
int xp_getmeminfo (xp_meminfo_t* mem)
{
#if defined(_WIN32) 
	#if (_WIN32_WINNT<0x0500)

	MEMORYSTATUS status;
	GlobalMemoryStatus(&status);
	mem->totalram = status.dwTotalPhys;
	mem->freeram = status.dwAvailPhys;
	mem->totalswap = status.dwTotalVirtual;
	mem->freeswap = status.dwAvailVirtual;

	#else

	MEMORYSTATUSEX status;
	if (GlobalMemoryStatusEx(&status) == FALSE) return -1;
	mem->totalram = status.ullTotalPhys;
	mem->freeram = status.ullAvailPhys;
	mem->totalswap = status.ullTotalVirtual;
	mem->freeswap = status.ullAvailVirtual;

	#endif

	mem->availram = mem->totalram - mem->freeram;
	mem->availswap = mem->totalswap - mem->freeswap;
	return 0;
#elif defined(__linux)

	struct sysinfo info;

	if (sysinfo (&info) == -1) return -1;
#ifdef XP_HAVE_SYS_SYSINFO_MEM_UNIT
	mem->totalram = info.totalram * info.mem_unit;
	mem->freeram = info.freeram * info.mem_unit;
	mem->totalswap = info.totalswap * info.mem_unit;
	mem->freeswap = info.freeswap * info.mem_unit;
#else
	mem->totalram = info.totalram;
	mem->freeram = info.freeram;
	mem->totalswap = info.totalswap;
	mem->freeswap = info.freeswap;
#endif

	mem->availram = mem->totalram - mem->freeram;
	mem->availswap = mem->totalswap - mem->freeswap;

/*
	xp_sio_t sio;
	xp_char_t buf[1024];
	xp_size_t idx;
	int match_mem = 0, match_swap = 0;

	if (xp_sio_open(&sio, 
		XP_TEXT("/proc/meminfo"), XP_TEXT("r")) == XP_NULL) return -1;

	for (idx = 0; idx < 6; idx++) mem[idx] = 0;

	while (xp_sio_gets(&sio, buf, sizeof(buf)) > 0) {
		xp_char_t* p = buf;

		while (xp_isspace(*p)) p++;
		if (p[0] == XP_CHAR('M') && p[1] == XP_CHAR('e') && 
		    p[2] == XP_CHAR('m') && p[3] == XP_CHAR(':')) {
			p += 4; match_mem = 1;
			for (idx = 0; idx < 3; idx++) {
				while (xp_isspace(*p)) p++;
				while (xp_isdigit(*p)) {
					mem[idx] = mem[idx] * 10 + (*p++ - XP_CHAR('0'));
				}
			}
		}
		else if (p[0] == XP_CHAR('S') && p[1] == XP_CHAR('w') &&
		         p[2] == XP_CHAR('a') && p[3] == 'p' && p[4] == XP_CHAR(':')) {
			p += 5; match_swap = 1;
			for (idx = 3; idx < 6; idx++) {
				while (xp_isspace(*p)) p++;
				while (xp_isdigit(*p)) {
					mem[idx] = mem[idx] * 10 + (*p++ - XP_CHAR('0'));
				}
			}
		}
		else if (!match_mem &&
		         xp_strcmpn(p, XP_TEXT("MemTotal:"), 9) == 0) {
			p += 9; while (xp_isspace(*p)) p++;
			while (xp_isdigit(*p)) mem[0] = mem[0] * 10 + (*p++ - XP_CHAR('0'));
		}
		else if (!match_mem && mem[0] > 0 &&
		         xp_strcmpn(p, XP_TEXT("MemFree:"), 8) == 0) {
			p += 8; while (xp_isspace(*p)) p++;
			while (xp_isdigit(*p)) mem[2] = mem[2] * 10 + (*p++ - XP_CHAR('0'));
			mem[1] = mem[0] - mem[2];
		}
		else if (!match_swap && 
		         xp_strcmpn(p, XP_TEXT("SwapTotal:"), 10) == 0) {
			p += 10; while (xp_isspace(*p)) p++;
			while (xp_isdigit(*p)) mem[3] = mem[3] * 10 + (*p++ - XP_CHAR('0'));
		}
		else if (!match_swap && mem[3] > 0 && 
		         xp_strcmpn(p, XP_TEXT("SwapFree:"), 9) == 0) {
			p += 9; while (xp_isspace(*p)) p++;
			while (xp_isdigit(*p)) mem[5] = mem[5] * 10 + (*p++ - XP_CHAR('0'));
			mem[4] = mem[3] - mem[5];
		}
	}
	xp_sio_close (&sio);

	if (!match_mem) { for (idx = 0; idx < 3; idx++) mem[idx] *= 1024; }
	if (!match_swap) { for (idx = 4; idx < 6; idx++) mem[idx] *= 1024; }
*/

	return 0;
#elif defined(__FreeBSD__)
	/*
	kvm_t* kvm;
	
	kvm = kvm_open (XP_NULL, XP_NULL, XP_NULL, O_RDONLY, "kvm_open");
	if (kvm == XP_NULL) return -1;

	kvm_close (kvm);
	return 0;
	*/
	return -1;
#else
	return -1;
#endif
}
